home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / mawk.zip / SCAN.C < prev    next >
C/C++ Source or Header  |  1991-04-09  |  18KB  |  695 lines

  1.  
  2. /********************************************
  3. scan.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the Awk programming language as defined in
  8. Aho, Kernighan and Weinberger, The AWK Programming Language,
  9. Addison-Wesley, 1988.
  10.  
  11. See the accompaning file, LIMITATIONS, for restrictions
  12. regarding modification and redistribution of this
  13. program in source or binary form.
  14. ********************************************/
  15.  
  16.  
  17. /* $Log:    scan.c,v $
  18.  * Revision 2.2  91/04/09  12:39:27  brennan
  19.  * added static to funct decls to satisfy STARDENT compiler
  20.  * 
  21.  * Revision 2.1  91/04/08  08:23:51  brennan
  22.  * VERSION 0.97
  23.  * 
  24. */
  25.  
  26.  
  27. #include  "mawk.h"
  28. #include  "sizes.h"
  29. #include  "scan.h"
  30. #include  "memory.h"
  31. #include  "field.h"
  32. #include  "init.h"
  33. #include  "fin.h"
  34. #include  "repl.h"
  35. #include  <fcntl.h>
  36. #include  <string.h>
  37. #include  "files.h"
  38.  
  39.  
  40. /* static functions */
  41. static void PROTO(buff_create, (char *) ) ;
  42. static int PROTO(slow_next, (void) ) ;
  43. static void PROTO(eat_comment, (void) ) ;
  44. static double PROTO(collect_decimal, (int, int *) ) ;
  45. static int PROTO(collect_string, (void) ) ;
  46. static int  PROTO(collect_RE, (void) ) ;
  47. static char *PROTO(rm_escape, (char *) ) ;
  48.  
  49.  
  50. /*-----------------------------
  51.   program file management
  52.  *----------------------------*/
  53.  
  54. static  unsigned char *buffer ;
  55. static  unsigned char *buffp ;  
  56.     /* unsigned so it works with 8 bit chars */
  57. static  int  program_fd = -1  ; 
  58. static  int  eof_flag ;
  59.  
  60.  
  61. static void buff_create(s)
  62.   char *s ;
  63. {
  64.   /* If program_fd == -1, program came from command line and s
  65.      is it, else s is a filename */
  66.  
  67.   if ( program_fd == -1 )
  68.   { buffer = buffp = (unsigned char *) s ; eof_flag = 1 ; }
  69.   else /* s is a filename, open it */
  70.   {
  71.     if ( s[0] == '-' && s[1] == 0 ) program_fd = 0 ;
  72.     else
  73.     if ( (program_fd = open(s, O_RDONLY, 0)) == -1 )
  74.     { errmsg( errno, "cannot open %s", s) ; mawk_exit(1) ; }
  75.  
  76.     buffp = buffer = (unsigned char *) zmalloc( BUFFSZ+1 ) ;
  77.  
  78.     eof_flag = fillbuff(program_fd, buffer, BUFFSZ) < BUFFSZ ;
  79.   }
  80. }
  81.  
  82. void scan_cleanup()
  83.   if ( program_fd >= 0 ) zfree(buffer, BUFFSZ+1) ;
  84.   if ( program_fd > 0 )  (void) close(program_fd) ;
  85.   scan_code['\n'] = SC_SPACE ;
  86. }
  87.  
  88.  
  89. void  scan_init(flag, p)
  90.   int flag ; /* on if program is from the command line */
  91.   char *p ;
  92.   if ( ! flag ) program_fd = 0 ;
  93.   buff_create(p) ;
  94.  
  95.   eat_nl() ; /* scan to first token */
  96.   if ( next() == 0 )  
  97.   { errmsg(0, "no program") ; mawk_exit(1) ; }
  98.   un_next() ;
  99. }
  100.  
  101. /*--------------------------------
  102.   global variables shared by yyparse() and yylex()
  103.  *-------------------------------*/
  104.  
  105. int  current_token = -1 ; 
  106. unsigned  token_lineno ;
  107. unsigned  compile_error_count ;
  108. int   paren_cnt ;
  109. int   brace_cnt ;
  110. int   print_flag ;  /* changes meaning of '>' */
  111. int   getline_flag ; /* changes meaning of '<' */
  112.  
  113. extern  YYSTYPE  yylval ;
  114.  
  115. /*----------------------------------------
  116.  file reading functions
  117.  next() and un_next(c) are macros in scan.h
  118.  
  119.  *---------------------*/
  120.  
  121. static  unsigned lineno = 1 ;
  122.  
  123. /* used to help distinguish / as divide or start of RE  */
  124.  
  125. static int can_precede_re[] =
  126. { MATCH, NOT_MATCH, COMMA, RBRACE, 
  127. LPAREN, NOT, P_OR, P_AND, NL,  -1 } ;
  128.  
  129. /* read one character -- slowly */
  130. static int slow_next()
  131.   if ( *buffp == 0  )
  132.       if ( !eof_flag ) 
  133.       { buffp = buffer ;
  134.         eof_flag = fillbuff(program_fd, buffer,BUFFSZ) < BUFFSZ ;
  135.       }
  136.  
  137.   return *buffp++ ; /* note can un_next() , eof which is zero */
  138. }
  139.  
  140. static void eat_comment()
  141. { register int c ;
  142.  
  143.   while ( (c = next()) != '\n' && scan_code[c] ) ;
  144.   un_next() ;
  145. }
  146.  
  147. void eat_nl() /* eat all space including newlines */
  148. {
  149.   while ( 1 )
  150.     switch( scan_code[next()] )
  151.     { 
  152.       case SC_COMMENT : 
  153.          eat_comment() ;
  154.          break ;
  155.          
  156.       case  SC_NL  :   lineno++ ;
  157.       /* fall thru  */
  158.       case  SC_SPACE  :   break ;
  159.       default :  
  160.           un_next() ; return ;
  161.     }
  162. }
  163.  
  164. int yylex()
  165.   register int c ;
  166.  
  167.   token_lineno = lineno ;
  168.  
  169. reswitch:
  170.  
  171.     switch( scan_code[c = next()] )
  172.     {
  173.       case  0  :  /* if no terminator on the line put one */
  174.           if ( (c = current_token) == RBRACE ||
  175.                 c == NL || c == SEMI_COLON ) ct_ret(EOF) ;
  176.           else
  177.           { un_next() ;  ct_ret(NL) ; }
  178.           
  179.       case  SC_SPACE  :   goto reswitch ;
  180.  
  181.       case  SC_COMMENT :
  182.           eat_comment() ; goto reswitch ;
  183.  
  184.       case  SC_NL  : 
  185.           lineno++ ; eat_nl() ;
  186.           ct_ret(NL) ;
  187.  
  188.       case SC_ESCAPE :
  189.           while ( scan_code[ c = next() ] == SC_SPACE ) ;
  190.           if ( c == '\n')
  191.           { token_lineno = ++lineno ; goto reswitch ; }
  192.           if ( c == 0 )  ct_ret(EOF) ;
  193.           un_next() ;
  194.           yylval.ival = '\\' ;
  195.           ct_ret(UNEXPECTED) ;
  196.  
  197.  
  198.       case  SC_SEMI_COLON  : 
  199.           eat_nl() ;
  200.           ct_ret(SEMI_COLON) ;
  201.  
  202.       case  SC_LBRACE :  
  203.           eat_nl() ; brace_cnt++ ;
  204.           ct_ret(LBRACE) ;
  205.  
  206.       case  SC_PLUS  :
  207.           test2_ret('+', INC, '=', ADD_ASG, PLUS ) ;
  208.  
  209.       case  SC_MINUS :
  210.           test2_ret('-', DEC, '=', SUB_ASG, MINUS ) ;
  211.  
  212.       case  SC_COMMA :  eat_nl() ; ct_ret(COMMA) ;
  213.  
  214.       case  SC_MUL  :  test1_ret('=', MUL_ASG, MUL) ;
  215.       case  SC_DIV :   
  216.           { int *p = can_precede_re ;
  217.  
  218.             do
  219.                 if ( *p == current_token )
  220.                     ct_ret( collect_RE() ) ;
  221.             while ( *p++ != -1 ) ;
  222.  
  223.             test1_ret( '=', DIV_ASG , DIV ) ;
  224.           }
  225.  
  226.       case  SC_MOD  :  test1_ret('=', MOD_ASG, MOD) ;
  227.       case  SC_POW :   test1_ret('=' , POW_ASG, POW) ;
  228.       case  SC_LPAREN : 
  229.           paren_cnt++ ;
  230.           ct_ret(LPAREN) ;
  231.  
  232.       case  SC_RPAREN : 
  233.           if ( --paren_cnt < 0 )
  234.           { compile_error( "extra ')'" ) ;
  235.             paren_cnt = 0 ;
  236.             goto reswitch ; }
  237.  
  238.           ct_ret(RPAREN) ;
  239.  
  240.       case  SC_LBOX   : ct_ret(LBOX) ;
  241.       case  SC_RBOX   : ct_ret(RBOX) ;
  242.  
  243.       case  SC_MATCH  : ct_ret(MATCH) ;
  244.  
  245.       case  SC_EQUAL  :
  246.           test1_ret( '=', EQ, ASSIGN ) ;
  247.  
  248.       case  SC_NOT : /* !  */
  249.           test2_ret('=', NEQ, '~', NOT_MATCH, NOT ) ;
  250.  
  251.       case  SC_LT  :  /* '<' */
  252.           if ( getline_flag )
  253.           { getline_flag = 0 ; ct_ret(IO_IN) ; }
  254.           else
  255.           { ct_ret( ifnext('=', LTE , LT) ) ; }
  256.  
  257.       case  SC_GT  :  /* '>' */
  258.           if ( print_flag && paren_cnt == 0 )
  259.           { print_flag = 0 ;
  260.             /* there are 3 types of IO_OUT 
  261.                -- build the error string in temp_buff */
  262.             temp_buff.string_buff[0] = '>' ;
  263.             if ( next() == '>' ) 
  264.             { 
  265.               yylval.ival = F_APPEND ;
  266.               temp_buff.string_buff[1] = '>' ;
  267.               temp_buff.string_buff[2] =  0 ;
  268.             }
  269.             else
  270.             { un_next() ; 
  271.               yylval.ival = F_TRUNC ; 
  272.               temp_buff.string_buff[1] = 0 ;
  273.             }
  274.             return current_token = IO_OUT ;
  275.           }
  276.  
  277.           ct_ret( ifnext('=', GTE , GT) ) ;
  278.  
  279.       case  SC_OR :
  280.           if ( next() == '|' ) 
  281.           { eat_nl() ; ct_ret(brace_cnt?OR:P_OR) ; }
  282.           else 
  283.           { un_next() ; 
  284.  
  285.             if ( print_flag && paren_cnt == 0 )
  286.             { print_flag = 0 ; 
  287.               yylval.ival = PIPE_OUT;
  288.               temp_buff.string_buff[0] = '|' ;
  289.               temp_buff.string_buff[1] = 0 ;
  290.               ct_ret(IO_OUT) ;
  291.             }
  292.             else  ct_ret(PIPE) ;
  293.           }
  294.  
  295.       case  SC_AND :
  296.           if ( next() == '&' )  
  297.           { eat_nl() ; ct_ret(brace_cnt?AND:P_AND) ; }
  298.           else 
  299.           { un_next() ; yylval.ival = '&' ; ct_ret(UNEXPECTED) ; }
  300.  
  301.       case  SC_QMARK  :  ct_ret(QMARK) ;
  302.       case  SC_COLON  :  ct_ret(COLON) ;
  303.       case  SC_RBRACE :
  304.           if ( --brace_cnt < 0 )
  305.           { compile_error("extra '}'" ) ;
  306.             brace_cnt = 0 ; goto reswitch ; }
  307.  
  308.           if ( (c = current_token) == NL || c == SEMI_COLON 
  309.                || c == SC_FAKE_SEMI_COLON  || c == RBRACE  )
  310.           { eat_nl() ; ct_ret(RBRACE) ; }
  311.  
  312.           brace_cnt++ ; un_next() ;
  313.           current_token = SC_FAKE_SEMI_COLON ;
  314.           return  SEMI_COLON ;
  315.  
  316.       case  SC_DIGIT  :
  317.       case  SC_DOT    :
  318.           { double d ;
  319.             int flag ;
  320.  
  321.             if ( (d = collect_decimal(c, &flag)) == 0.0 )
  322.                 if ( flag )  ct_ret(flag) ;
  323.                 else  yylval.cp = &cell_zero ;
  324.             else if ( d == 1.0 ) yylval.cp = &cell_one ;
  325.             else 
  326.             { yylval.cp = new_CELL() ;
  327.               yylval.cp->type = C_DOUBLE ;
  328.               yylval.cp->dval = d ; 
  329.             }
  330.             ct_ret( CONSTANT ) ;
  331.           }
  332.  
  333.       case  SC_DOLLAR :  /* '$' */
  334.           { double d ;
  335.             int flag ;
  336.  
  337.             while ( scan_code[c = next()] == SC_SPACE )  ;
  338.             if ( scan_code[c] != SC_DIGIT &&
  339.                  scan_code[c] != SC_DOT )
  340.             { un_next() ; ct_ret(DOLLAR) ; }
  341.             /* compute field address at compile time */
  342.             if ( (d = collect_decimal(c, &flag)) == 0.0 )
  343.                 if ( flag )  ct_ret(flag) ; /* an error */
  344.                 else  yylval.cp = &field[0] ;
  345.             else
  346.             { int k = (int) d ;
  347.  
  348.               if ( k > MAX_FIELD )
  349.               { compile_error(
  350.                    "maximum field index(%d) exceeded" , k ) ;
  351.                 k = MAX_FIELD ;
  352.               }
  353.               else  yylval.cp = &field[k] ;
  354.             }
  355.  
  356.             ct_ret(FIELD) ;
  357.           }
  358.  
  359.       case  SC_DQUOTE :
  360.           return current_token = collect_string() ;
  361.  
  362.       case  SC_IDCHAR : /* collect an identifier */
  363.             { unsigned char *p =
  364.                     (unsigned char *)temp_buff.string_buff + 1 ;
  365.               SYMTAB *stp ;
  366.  
  367.               temp_buff.string_buff[0] = c ;
  368.  
  369.               while ( 
  370.                 (c = scan_code[ *p++ = next()]) == SC_IDCHAR ||
  371.                        c == SC_DIGIT )  ;
  372.               
  373.               un_next() ; * --p = 0 ;
  374.  
  375.               switch( (stp = find(temp_buff.string_buff))->type )
  376.               { case ST_NONE :  
  377.                   /* check for function call before defined */
  378.                       if ( next() == '(' )
  379.                       { stp->type = ST_FUNCT ;
  380.                         stp->stval.fbp = (FBLOCK *)
  381.                                 zmalloc(sizeof(FBLOCK)) ;
  382.                         stp->stval.fbp->name = stp->name ;
  383.                         stp->stval.fbp->code = (INST *) 0 ;
  384.                         yylval.fbp = stp->stval.fbp ;
  385.                         current_token = FUNCT_ID ;
  386.                       }
  387.                       else
  388.                       { yylval.stp = stp ;
  389.                         current_token = ID ;
  390.                       }
  391.                       un_next() ;
  392.                       break ;
  393.                         
  394.                 case ST_VAR :
  395.                 case  ST_ARRAY :
  396.                 case  ST_LOCAL_NONE :
  397.                 case  ST_LOCAL_VAR :
  398.                 case  ST_LOCAL_ARRAY :
  399.  
  400.                       yylval.stp = stp ;
  401.                       current_token = ID ;
  402.                       break ;
  403.  
  404.                 case ST_FUNCT :
  405.                       yylval.fbp = stp->stval.fbp ;
  406.                       current_token = FUNCT_ID ;
  407.                       break ;
  408.  
  409.                 case ST_KEYWORD :  
  410.                       current_token = stp->stval.kw ;
  411.                       break ;
  412.  
  413.                 case  ST_BUILTIN :
  414.                       yylval.bip = stp->stval.bip ;
  415.                       current_token = BUILTIN ;
  416.                       break ;
  417.  
  418.                 case  ST_FIELD  :
  419.                       yylval.cp = stp->stval.cp ;
  420.                       current_token = FIELD ;
  421.                       break ;
  422.  
  423.                 case  ST_LENGTH  :
  424.                     { CELL *bi_length() ;
  425.                       static BI_REC length_bi_rec =
  426.                       { "length", bi_length, 1, 1 } ;
  427.  
  428.                       while ( scan_code[ c = next() ] == SC_SPACE ) ;
  429.                       un_next() ;
  430.  
  431.                       if ( c == '(' )
  432.                       { yylval.bip = &length_bi_rec ;
  433.                         current_token = BUILTIN ;
  434.                       }
  435.                       else current_token = LENGTH ;
  436.                     }
  437.                     break ;
  438.  
  439.                 default : 
  440.                       bozo("find returned bad st type") ;
  441.               }
  442.               return  current_token  ;
  443.             }
  444.  
  445.  
  446.       case  SC_UNEXPECTED :
  447.             yylval.ival = c & 0xff ;
  448.             ct_ret(UNEXPECTED) ;
  449.     }
  450.     return  0 ; /* never get here make lint happy */
  451. }
  452.  
  453. /* collect a decimal constant in temp_buff.
  454.    Return the value and error conditions by reference */
  455.  
  456. static double collect_decimal(c, flag)
  457.   int c ; int *flag ;
  458. { register unsigned char *p = (unsigned char*) temp_buff.string_buff + 1;
  459.   unsigned char *endp ;
  460.   double d ;
  461.  
  462.   *flag = 0 ;
  463.   temp_buff.string_buff[0] = c ;
  464.  
  465.   if ( c == '.' )
  466.   { if ( scan_code[*p++ = next()] != SC_DIGIT )
  467.     { *flag = UNEXPECTED ; yylval.ival = '.' ;
  468.       return 0.0 ; }
  469.   }
  470.   else
  471.   {  while ( scan_code[*p++ = next()] == SC_DIGIT ) ;
  472.      if ( p[-1] != '.' )
  473.      { un_next() ; p-- ; }
  474.   }
  475.   /* get rest of digits after decimal point */
  476.   while ( scan_code[*p++ = next()] == SC_DIGIT )  ;
  477.  
  478.   /* check for exponent */
  479.   if ( p[-1] != 'e' && p[-1] != 'E' )
  480.   { un_next() ; * --p = 0 ; }
  481.   else  /* get the exponent */
  482.     if ( scan_code[*p = next()] != SC_DIGIT &&
  483.          *p != '-' && *p != '+' )
  484.     { *++p = 0 ; *flag = BAD_DECIMAL ;
  485.       return 0.0 ; }
  486.     else  /* get the rest of the exponent */
  487.     { p++ ;
  488.       while ( scan_code[*p++ = next()] == SC_DIGIT )  ;
  489.       un_next() ; * --p = 0 ;
  490.     }
  491.  
  492.   errno = 0 ; /* check for overflow/underflow */
  493.   d = strtod( temp_buff.string_buff, &endp ) ;
  494.   if ( errno )
  495.       compile_error( "%s : decimal %sflow" , temp_buff.string_buff,
  496.         d == 0.0 ? "under" : "over") ;
  497.   if ( endp != p )
  498.   { *flag = BAD_DECIMAL ; return 0.0 ; }
  499.   return d ;
  500. }
  501.  
  502. /*----------  process escape characters ---------------*/
  503.  
  504. static char hex_val['f' - 'A' + 1] = {
  505. 10,11,12,13,14,15, 0, 0,
  506.  0, 0, 0, 0, 0, 0, 0, 0,
  507.  0, 0, 0, 0, 0, 0, 0, 0,
  508.  0, 0, 0, 0, 0, 0, 0, 0,
  509. 10,11,12,13,14,15 } ;
  510.  
  511. #define isoctal(x)  ((x)>='0'&&(x)<='7')
  512.  
  513. #define  hex_value(x)   hex_val[(x)-'A']
  514.  
  515. #define ishex(x) (scan_code[x] == SC_DIGIT ||\
  516.                   'A' <= (x) && (x) <= 'f' && hex_value(x))
  517.  
  518. static int PROTO(octal, (char **)) ;
  519. static int PROTO(hex, (char **)) ;
  520.  
  521. /* process one , two or three octal digits
  522.    moving a pointer forward by reference */
  523. static int octal( start_p )
  524.   char **start_p ;
  525. { register char *p = *start_p ;
  526.   register unsigned x ;
  527.  
  528.   x = *p++ - '0' ;
  529.   if ( isoctal(*p) )
  530.   {
  531.     x = (x<<3) + *p++ - '0' ;
  532.     if ( isoctal(*p) )   x = (x<<3) + *p++ - '0' ;
  533.   }
  534.   *start_p = p ;
  535.   return  x & 0xff ;
  536. }
  537.  
  538. /* process one or two hex digits
  539.    moving a pointer forward by reference */
  540.  
  541. static int  hex( start_p )
  542.   unsigned char **start_p ;
  543. { register unsigned char *p = *start_p ;
  544.   register unsigned x ;
  545.   unsigned t ;
  546.  
  547.   if ( scan_code[*p] == SC_DIGIT )
  548.         x = *p++ - '0' ;
  549.   else  x = hex_value(*p++) ;
  550.  
  551.   if ( scan_code[*p] == SC_DIGIT )
  552.         x = (x<<4) + *p++ - '0' ;
  553.   else
  554.   if ( 'A' <= *p && *p <= 'f' && (t = hex_value(*p)) )
  555.   { x = (x<<4) + t ; p++ ; }
  556.  
  557.   *start_p = p ;
  558.   return x ;
  559. }
  560.  
  561. static char escape_test[] = 
  562.   "n\nt\tb\br\rf\fa\07v\013\\\\\"\"\'\'" ;
  563.  
  564. /* process the escape characters in a string, in place . */
  565.  
  566. static char *rm_escape(s)
  567.   char *s ;
  568. { register char *p, *q ;
  569.   char *t ;
  570.  
  571.   q = p = s ;
  572.  
  573.   while ( *p )
  574.       if ( *p == '\\' )
  575.       { 
  576.         if ( t = strchr(escape_test, * ++p) )
  577.         { 
  578.           p++ ; *q++ = t[1] ; 
  579.         }
  580.         else
  581.         if ( isoctal(*p) ) 
  582.         {
  583.           t = p ;  *q++ = octal(&t) ; p = t ;
  584.         }
  585.         else
  586.         if ( *p == 'x' && ishex(*(unsigned char*)(p+1)) )
  587.         {
  588.           t = p+1 ; *q++ = hex(&t) ; p = t ;
  589.         }
  590.         else  /* not an escape sequence */
  591.         { 
  592.           *q++ = '\\' ; *q++ = *p++ ;
  593.         }
  594.       }
  595.       else  *q++ = *p++ ;
  596.  
  597.   *q = 0 ;
  598.   return s ;
  599. }
  600.  
  601. static  int  collect_string()
  602. { register unsigned char *p = (unsigned char *)temp_buff.string_buff ;
  603.   int c ;
  604.   int e_flag = 0 ; /* on if have an escape char */
  605.  
  606.   while ( 1 )
  607.       switch( scan_code[ *p++ = next() ] )
  608.       { case  SC_DQUOTE : /* done */
  609.               * --p = 0 ;  goto out ;
  610.  
  611.         case  SC_NL :
  612.               p[-1] = 0 ;
  613.               /* fall thru */
  614.  
  615.         case  0 :   /* unterminated string */
  616.               compile_error(
  617.               "runaway string constant \"%.10s ..." ,
  618.               temp_buff.string_buff, token_lineno ) ;
  619.               mawk_exit(1) ;
  620.  
  621.         case SC_ESCAPE :
  622.               if ( (c = next()) == '\n' )
  623.               { p-- ; lineno++ ; }
  624.               else  
  625.                 if ( c == 0 )  un_next() ;   
  626.                 else 
  627.                 { *p++ = c ; e_flag = 1 ; }
  628.  
  629.               break ;
  630.  
  631.         default : break ;
  632.       }
  633.  
  634. out:
  635.     yylval.cp = new_CELL() ;
  636.     yylval.cp->type = C_STRING ;
  637.     yylval.cp->ptr = (PTR) new_STRING(
  638.          e_flag ? rm_escape( temp_buff.string_buff ) 
  639.                 : temp_buff.string_buff ) ;
  640.     return  CONSTANT ;
  641. }
  642.  
  643.  
  644. static  int  collect_RE()
  645. { register unsigned char *p = (unsigned char*) temp_buff.string_buff ;
  646.   int c ;
  647.   STRING *sval ;
  648.  
  649.   while ( 1 )
  650.       switch( scan_code[ *p++ = next() ] )
  651.       { case  SC_DIV : /* done */
  652.               * --p = 0 ;  goto out ;
  653.  
  654.         case  SC_NL :
  655.               p[-1] = 0 ;
  656.               /* fall thru */
  657.  
  658.         case  0 :   /* unterminated re */
  659.               compile_error(
  660.               "runaway regular expression /%.10s ..." ,
  661.               temp_buff.string_buff, token_lineno ) ;
  662.               mawk_exit(1) ;
  663.  
  664.         case SC_ESCAPE :
  665.               switch( c = next() )
  666.               { case '/' :  
  667.                       p[-1] = '/' ; break ;
  668.  
  669.                 case '\n' :
  670.                       p-- ;  break ;
  671.  
  672.                 case  0   :
  673.                       un_next() ;  break ;
  674.  
  675.                 default :
  676.                       *p++ = c ; break ;
  677.               }
  678.               break ;
  679.       }
  680.  
  681. out:
  682.   /* now we've got the RE, so compile it */
  683.   sval = new_STRING( temp_buff.string_buff ) ;
  684.   yylval.cp = new_CELL() ;
  685.   yylval.cp->type = C_RE ;
  686.   yylval.cp->ptr = re_compile(sval) ;
  687.   free_STRING(sval) ;
  688.   return RE ;
  689. }
  690.  
  691.